﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Kinect;
using Kinect_Dance.Framework;
using Kinect_Dance.Objects;


namespace Kinect_Dance.Screens
{
    class GameplayScreen : Microsoft.Xna.Framework.Game
    {

        KinectSensor kinect;
        Skeleton skeleton;
        Skeleton[] skeletonData;
        Texture2D colorVideo;
        Texture2D depthVideo;
        Texture2D jointTexture;
        SpriteBatch sp;
        private MainGame mGame;
        C_ManageCircle manageCircle;
        Joint skHead;
        Joint skHandLeft;
        Joint skHandRight;
        Joint skFootLeft;
        Joint skFootRight;
        C_pCircle vbHead;
        C_pCircle vbHandLeft;
        C_pCircle vbHandRight;
        C_pCircle vbFootLeft;
        C_pCircle vbFootRight;

        public GameplayScreen(MainGame g)
        {
            this.mGame = g;
            try
            {
                manageCircle = new C_ManageCircle();
                kinect = KinectSensor.KinectSensors[0];
                //kinect.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);
                kinect.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
                //kinect.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(kinect_ColorFrameReady);
                kinect.SkeletonStream.Enable();
                kinect.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(kinect_AllFramesReady);
                kinect.Start();
                colorVideo = new Texture2D(mGame.GraphicsDevice, kinect.ColorStream.FrameWidth, kinect.ColorStream.FrameHeight);
                depthVideo = new Texture2D(mGame.GraphicsDevice, kinect.DepthStream.FrameWidth, kinect.ColorStream.FrameHeight);
                jointTexture = mGame.Content.Load<Texture2D>("Images/joint");
                manageCircle.LoadFile("10");

                foreach (C_pCircle p in manageCircle.ListCircle)
                {
                    p.pTexture = mGame.Content.Load<Texture2D>("Images/joint");
                    //switch (p.type)
                    //{
                    //    case JointType.Head:
                    //        p.pTexture = mGame.Content.Load<Texture2D>("Images/joint");
                    //        break;
                    //    case JointType.FootLeft:
                    //        p.pTexture = mGame.Content.Load<Texture2D>("Images/joint");
                    //        break;
                    //    case JointType.FootRight:
                    //        p.pTexture = mGame.Content.Load<Texture2D>("Images/joint");
                    //        break;
                    //    case JointType.HandLeft:
                    //        p.pTexture = mGame.Content.Load<Texture2D>("Images/joint");
                    //        break;
                    //    case JointType.HandRight:
                    //        p.pTexture = mGame.Content.Load<Texture2D>("Images/joint");
                    //        break;
                    //    default:
                    //        break;
                    //}
                }
            }
            catch (Exception e)
            {

            }
        }

        void kinect_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            throw new NotImplementedException();
        }

        protected override void Draw(GameTime gameTime)
        {
            mGame.GraphicsDevice.Clear(Color.White);
            sp.Begin();
            sp.Draw(colorVideo, new Rectangle(0, 0, 800, 600), Color.White);
            //sp.Draw(depthVideo, new Rectangle(480, 0, 320, 160), Color.White);
            //DrawSkeleton(sp, new Vector2(mGame.GraphicsDevice.Viewport.Width, mGame.GraphicsDevice.Viewport.Height), jointTexture);
            manageCircle.draw(gameTime, this.sp);
            sp.End();
            base.Draw(gameTime);
        }

        protected override void Update(GameTime gameTime)
        {
            
            base.Update(gameTime);
        }

        protected override void Initialize()
        {
            
            base.Initialize();
        }

        void kinect_AllFramesReady(object sender, AllFramesReadyEventArgs e)
        {
            // Color
            ColorImageFrame colorVideoFrame = e.OpenColorImageFrame();
            if (colorVideoFrame != null)
            {
                //Create array for pixel data and copy it from the image frame
                Byte[] pixelData = new Byte[colorVideoFrame.PixelDataLength];
                colorVideoFrame.CopyPixelDataTo(pixelData);
                Byte[] bgraPixelData = new Byte[colorVideoFrame.PixelDataLength];
                for (int i = 0; i < bgraPixelData.Length; i += 4)
                {
                    bgraPixelData[i] = pixelData[i + 2];
                    bgraPixelData[i + 1] = pixelData[i + 1];
                    bgraPixelData[i + 2] = pixelData[i];
                    bgraPixelData[i + 3] = (Byte)255; // //The video comes with 0 alpha so it is transparent
                }

                colorVideo = new Texture2D(mGame.GraphicsDevice, colorVideoFrame.Width, colorVideoFrame.Height);
                colorVideo.SetData(bgraPixelData);
            }


            // Depth
            DepthImageFrame depthVideoFrame = e.OpenDepthImageFrame();
            if (depthVideoFrame != null)
            {
                //Create array for pixel data and copy it from the image frame
                short[] pixelData = new short[depthVideoFrame.PixelDataLength];
                depthVideoFrame.CopyPixelDataTo(pixelData);
                depthVideo = new Texture2D(mGame.GraphicsDevice, kinect.DepthStream.FrameWidth, kinect.DepthStream.FrameHeight);
                depthVideo.SetData(ConvertDepthFrame(pixelData, kinect.DepthStream));
            }

            // Skeleton
            using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
            {
                if (skeletonFrame != null)
                {
                    if ((skeletonData == null) || (this.skeletonData.Length != skeletonFrame.SkeletonArrayLength))
                    {
                        this.skeletonData = new Skeleton[skeletonFrame.SkeletonArrayLength];

                    }
                    //Copy the skeleton data to our array
                    skeletonFrame.CopySkeletonDataTo(skeletonData);
                }
            }
            if (skeletonData != null)
            {
                var sk = skeletonData.Where(s => s.TrackingState == SkeletonTrackingState.Tracked).FirstOrDefault();
                if (sk != null)
                {
                    //  double height = Height(sk);
                    // myHeight = height;
                }
                foreach (Skeleton ske in skeletonData)
                {
                    if (ske.TrackingState == SkeletonTrackingState.Tracked)
                    {
                        skeleton = ske;
                        foreach (Joint j in skeleton.Joints)
                        {
                            switch (j.JointType)
                            {
                                case JointType.Head:
                                    skHead = j;
                                    break;
                                case JointType.HandLeft:
                                    skHandLeft = j;
                                    break;
                                case JointType.HandRight:
                                    skHandRight = j;
                                    break;
                                case JointType.FootRight:
                                    skFootRight = j;
                                    break;
                                case JointType.FootLeft:
                                    skFootLeft = j;
                                    break;
                                default:
                                    break;
                            }
                        }
                    }
                }
            }
        }

        protected override void OnExiting(object sender, EventArgs args)
        {
            kinect.Stop();
            base.OnExiting(sender, args);
        }
        
        protected override void LoadContent()
        {
            base.LoadContent();
        }

        protected override void UnloadContent()
        {
            base.UnloadContent();
        }

        public void gameUpdate(GameTime gt)
        {
            Update(gt);
        }

        public void gameDraw(GameTime gt, SpriteBatch sp)
        {
            this.sp = sp;
            Draw(gt);
        }

        private void DrawSkeleton(SpriteBatch spriteBatch, Vector2 resolution, Texture2D img)
        {
            if (skeleton != null)
            {
                foreach (Joint joint in skeleton.Joints)
                {
                    if (joint.JointType == JointType.Head ||
                        joint.JointType == JointType.FootLeft || joint.JointType == JointType.FootRight || 
                        joint.JointType == JointType.HandLeft || joint.JointType == JointType.HandRight)
                    {
                        Vector2 position = new Vector2((((0.5f * joint.Position.X) + 0.5f) * (resolution.X)), (((-0.5f * joint.Position.Y) + 0.5f) * (resolution.Y)));
                        spriteBatch.Draw(img, new Rectangle(Convert.ToInt32(position.X), Convert.ToInt32(position.Y), 10, 10), Color.Red);
                
                    }
                }
            }
        }

        private byte[] ConvertDepthFrame(short[] depthFrame, DepthImageStream depthImageStream)
        {
            int redIndex = 0;
            int blueIndex = 1;
            int greenIndex = 2;
            int alphaIndex = 3;

            byte[] depthFrame32 = new byte[depthImageStream.FrameWidth * depthImageStream.FrameHeight * 4];

            for (int i16 = 0, i32 = 0; i16 < depthFrame.Length && i32 < depthFrame32.Length; i32 += 4, i16++)
            {
                int player = depthFrame[i16] & DepthImageFrame.PlayerIndexBitmask;
                int realDepth = depthFrame[i16] >> DepthImageFrame.PlayerIndexBitmaskWidth;

                // transform 13-bit depth information into an 8-bit intensity appropriate
                // for display (we disregard information in most significant bit)
                byte intensity = (byte)(~(realDepth >> 4));

                depthFrame32[i32 + redIndex] = (byte)intensity;
                depthFrame32[i32 + blueIndex] = (byte)intensity;
                depthFrame32[i32 + greenIndex] = (byte)intensity;
                depthFrame32[i32 + alphaIndex] = 255;
            }

            return depthFrame32;
        } 
    }
}
